package my.edu.model.commodity.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import my.edu.common.constant.MessageConstant;
import my.edu.common.constant.OrderConstant;
import my.edu.common.domain.OrderProductDetail;
import my.edu.common.domain.PageDTO;
import my.edu.common.domain.PageVO;
import my.edu.common.domain.purchase.PriceAndQuantity;
import my.edu.common.domain.purchase.ProductWithHighPrice;
import my.edu.common.enumeration.OrderType;
import my.edu.common.exception.*;
import my.edu.common.utils.PageUtils;
import my.edu.model.commodity.entity.ProductCategory;
import my.edu.model.commodity.entity.dto.ProductDTO;
import my.edu.model.commodity.entity.dto.ProductSearchDTO;
import my.edu.model.commodity.entity.vo.ProductReportVO;
import my.edu.model.commodity.entity.vo.ProductVO;
import my.edu.model.information.entity.Supplier;
import my.edu.model.information.service.ISupplierService;
import my.edu.utils.OrderDetailServiceUtil;
import my.edu.utils.OrderServiceUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import my.edu.model.commodity.entity.Product;
import my.edu.model.commodity.mapper.ProductMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {

    @Autowired
    private IProductCategoryService productCategoryService;
    @Autowired
    private ISupplierService supplierService;


    @Override
    @Transactional
    public void savenew(ProductDTO productDTO) {
        //检查类别
        ProductCategory category = productCategoryService.getById(productDTO.getCategoryId());
        if (category == null || category.getStatus().equals(0))
            throw new CategoryException(MessageConstant.CATEGORIES_NOT_AVAILABLE);
        //检查供应商
        Supplier supplier = supplierService.getById(productDTO.getDefaultSupplierId());
        if (supplier == null || supplier.getStatus().equals(0))
            throw new SupplierException(MessageConstant.SUPPLIER_NOT_AVAILABLE);
        if (productDTO.getInitialQuantity()==null)productDTO.setInitialQuantity(0);
        productDTO.setCurrentStock(productDTO.getInitialQuantity());
        //检查编号
        if (productDTO.getProductNo() != null && !productDTO.getProductNo().isBlank()) {
            Product product = getOne(Wrappers.lambdaQuery(Product.class).eq(Product::getProductNo, productDTO.getProductNo()));
            if (product != null)
                throw new BillsException(MessageConstant.PRODUCT_NO_EXIST);
        }
        Product product = BeanUtil.toBean(productDTO, Product.class);
        product.setStatus(1);
        save(product);
    }

    @Override
    public PageVO<ProductVO> listAll(PageDTO pageDTO, ProductSearchDTO productSearchDTO) {
        MPJLambdaWrapper<Product> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(Product.class, ProductVO.class)
                .selectAs(ProductCategory::getCategoryName, ProductVO::getCategoryName)
                .selectAs(Supplier::getSupplierName, ProductVO::getDefaultSupplierName)
                .leftJoin(ProductCategory.class, ProductCategory::getId, Product::getCategoryId)
                .leftJoin(Supplier.class, Supplier::getId, Product::getDefaultSupplierId)
                .like(productSearchDTO.getProductNo()!=null&&!productSearchDTO.getProductNo().isBlank(), Product::getProductNo, productSearchDTO.getProductNo())
                .like(productSearchDTO.getBrand()!=null&&!productSearchDTO.getBrand().isBlank(), Product::getBrand, productSearchDTO.getBrand())
                .like(productSearchDTO.getProductName()!=null&&!productSearchDTO.getProductName().isBlank(), Product::getProductName, productSearchDTO.getProductName())
                .eq(productSearchDTO.getCategoryId()!=null&&productSearchDTO.getCategoryId()!=0, Product::getCategoryId, productSearchDTO.getCategoryId())
                .eq(productSearchDTO.getStatus()!=null, Product::getStatus, productSearchDTO.getStatus())
                .eq(productSearchDTO.getDefaultSupplierId()!=null&&productSearchDTO.getDefaultSupplierId()!=0, Product::getDefaultSupplierId, productSearchDTO.getDefaultSupplierId())
                .or()
                .eq(productSearchDTO.getCategoryId()!=null&&productSearchDTO.getCategoryId()!=0,ProductCategory::getParentId, productSearchDTO.getCategoryId())
                .orderByAsc(Product::getId)
        ;
        Page<ProductVO> productVOPage = baseMapper.selectJoinPage(new Page<>(pageDTO.getPage(), pageDTO.getSize()), ProductVO.class, wrapper);
        return PageUtils.toPage(productVOPage) ;
    }

    @Override
    public ProductVO getVOById(Long id) {
        MPJLambdaWrapper<Product> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(Product.class, ProductVO.class)
                .selectAs(ProductCategory::getCategoryName, ProductVO::getCategoryName)
                .selectAs(Supplier::getSupplierName, ProductVO::getDefaultSupplierName)
                .leftJoin(ProductCategory.class, ProductCategory::getId, Product::getCategoryId)
                .leftJoin(Supplier.class, Supplier::getId, Product::getDefaultSupplierId)
                .eq(Product::getId, id);
        ProductVO vo = baseMapper.selectJoinOne(ProductVO.class, wrapper);
        return vo;
    }

    @Override
    @Transactional
    public void updateByDTO(ProductDTO productDTO) {
        if (productDTO.getId() == null)
            throw new CategoryException(MessageConstant.CATEGORIES_NOT_AVAILABLE);
        //检查类别
        ProductCategory category = productCategoryService.getById(productDTO.getCategoryId());
        if (category == null || category.getStatus().equals(0))
            throw new CanNotFoundException(MessageConstant.CAN_NOT_FOUND);
        //检查供应商
        Supplier supplier = supplierService.getById(productDTO.getDefaultSupplierId());
        if (supplier == null || supplier.getStatus().equals(0))
            throw new SupplierException(MessageConstant.SUPPLIER_NOT_AVAILABLE);
        //检查编号
        if (productDTO.getProductNo() != null && !productDTO.getProductNo().isBlank()) {
            List<Product> list = list(Wrappers.lambdaQuery(Product.class).eq(Product::getProductNo, productDTO.getProductNo()));
            if (list.size()>1||list.size()==1&&!list.get(0).getId().equals(productDTO.getId()))
                throw new BillsException(MessageConstant.PRODUCT_NO_EXIST);
        }
        Product byId = getById(productDTO.getId());
        BeanUtil.copyProperties(productDTO, byId);
        updateById(byId);
    }

    @Override
    @Transactional
    public void addCurrentStock(List<OrderProductDetail> orderProductDetailList) {
        //建立map，键为productid，值为数量
        Map<Long, Integer> collect = getIdToStock(orderProductDetailList);
        addCurrentStock(collect);
    }

    @Override
    @Transactional
    public void subCurrentStock(List<OrderProductDetail> orderProductDetailList) {
        //建立map，键为productid，值为数量
        Map<Long, Integer> collect = getIdToStock(orderProductDetailList);
        subCurrentStock(collect);
    }

    @Override
    @Transactional
    public void addCurrentStock(Map<Long, Integer> collect) {
        if (collect.isEmpty())return;
        // 查询当前库存
        List<Product> productList = list(Wrappers.<Product>lambdaQuery()
                .in(Product::getId, collect.keySet()));

        // 更新库存
        List<Product> updatedProducts = productList.stream()
                .peek(product -> {
                    Integer increment = collect.get(product.getId());
                    if (increment != null) {
                        product.setCurrentStock(product.getCurrentStock() + increment); // 更新库存
                    }
                })
                .collect(Collectors.toList());

        // 批量更新
        if (!updatedProducts.isEmpty()) {
            updateBatchById(updatedProducts);
        }
    }

    @Override
    @Transactional
    public void subCurrentStock(Map<Long, Integer> collect) {
        if (collect.isEmpty())return;
        // 查询当前库存
        List<Product> productList = list(Wrappers.<Product>lambdaQuery()
                .in(Product::getId, collect.keySet()));
        // 更新库存
        List<Product> updatedProducts = productList.stream()
                .peek(product -> {
                    Integer increment = collect.get(product.getId());
                    if (increment != null) {
                        product.setCurrentStock(product.getCurrentStock() - increment); // 更新库存
                    }
                })
                .collect(Collectors.toList());
        // 批量更新
        if (!updatedProducts.isEmpty()) {
            updateBatchById(updatedProducts);
        }
    }


    @Override
    public PriceAndQuantity chackAndGetTotal(List< ? extends OrderProductDetail>  productDetailDTOList, String status) {
        for (OrderProductDetail orderProductDetail : productDetailDTOList) {
            if (orderProductDetail.getIsGift()==null)orderProductDetail.setIsGift(0);
            if (orderProductDetail.getIsGift() == 1) {
                orderProductDetail.setCurrentPrice(BigDecimal.ZERO);
                orderProductDetail.setTaxInclusivePrice(BigDecimal.ZERO);
                orderProductDetail.setDiscountAmount(BigDecimal.ZERO);
                orderProductDetail.setTaxAmount(BigDecimal.ZERO);
                orderProductDetail.setPriceTaxTotal(BigDecimal.ZERO);
            }
        }
        //总数量
        Integer totalQuantity = 0;
        //总金额
        BigDecimal totalPrice = new BigDecimal(0);
        //预警商品
        ProductWithHighPrice warnPurchasePriceList=new ProductWithHighPrice(productDetailDTOList.get(0).getCurrentOrderType(), new ArrayList<>());
        //获取所有单据的商品id
        List<Long> productIdList = productDetailDTOList.stream().map(OrderProductDetail::getProductId).toList();
        //获取对应商品的信息
        List<Product> productList = list(Wrappers.<Product>lambdaQuery().in(Product::getId, productIdList));
        if (productList.isEmpty()) throw new BillsException(MessageConstant.PRODUCT_NOT_FOUND);
        //遍历商品信息
        for (Product product : productList) {
            //获取商品信息
            OrderProductDetail detailDTO = productDetailDTOList.stream().filter(i -> i.getProductId().equals(product.getId())).findFirst().orElse(null);
            if (detailDTO == null)throw new BillsException(MessageConstant.PRODUCT_NOT_FOUND);
            //设置金额字段
            OrderDetailServiceUtil.setAmount(detailDTO);
            OrderType currentOrderType = detailDTO.getCurrentOrderType();
            //检查库存商品状态
            if (product.getStatus() == 0) {
                throw new BillsException("商品："+product.getProductNo() + product.getProductName() + "已停用！");
            }
            //当前没有忽视检查不合规价格的商品以及非赠品
            if ((status == null || !status.equals(OrderConstant.IGNORE_PRICE)) && detailDTO.getIsGift() == 0) {
                //如果购货检查是否有高价
                if (currentOrderType.equals(OrderType.PURCHASE_PRICE)&&product.getHighestPurchasePrice().compareTo(detailDTO.getCurrentPrice()) < 0) {
                    warnPurchasePriceList.add(product.getId(), product.getProductName(), detailDTO.getCurrentPrice(), product.getHighestPurchasePrice());
                }
                //如果销货检查是否低价
                if (currentOrderType.equals(OrderType.SALE_PRICE)&&product.getLowestSalesPrice().compareTo(detailDTO.getCurrentPrice())>0){
                    warnPurchasePriceList.add(product.getId(), product.getProductName(), detailDTO.getCurrentPrice(), product.getLowestSalesPrice());
                }
            }
            totalQuantity += detailDTO.getQuantity();
            //如果是退货就检查并乘以可退数量
            totalPrice = totalPrice.add(detailDTO.getPriceTaxTotal());
        }
        //返回所有高价商品
        if (!warnPurchasePriceList.isEmpty()) throw new OverHighPriceException(warnPurchasePriceList);
        if (totalQuantity == 0) throw new BillsException(MessageConstant.Quantity_IS_ZERO);
        return new PriceAndQuantity(totalQuantity, totalPrice);
    }

    @Override
    @Transactional
    public void addCurrentStockAndSetLastPurchasePrice(List<OrderProductDetail> orderProductDetails) {
        //建立map，键为productid，值为数量
        Map<Long, Integer> idToQuantityMap = getIdToStock(orderProductDetails);
        Map<Long, BigDecimal> idToPurchasePriceMap = orderProductDetails.stream()
                .collect(Collectors.toMap(
                        OrderProductDetail::getProductId,
                        OrderProductDetail::getCurrentPrice,
                        (existingPrice, newPrice) -> existingPrice // 保留第一个遇到的价格
                ));
        // 查询当前库存
        List<Product> productList = list(Wrappers.<Product>lambdaQuery()
                .in(Product::getId, idToQuantityMap.keySet()));

        // 更新库存
        List<Product> updatedProducts = productList.stream()
                .peek(product -> {
                    Integer increment = idToQuantityMap.get(product.getId());
                    if (increment != null) {
                        product.setCurrentStock(product.getCurrentStock() + increment); // 更新库存
                    }
                    product.setLatestPurchasePrice(idToPurchasePriceMap.get(product.getId()));
                })
                .collect(Collectors.toList());

        // 批量更新
        if (!updatedProducts.isEmpty()) {
            updateBatchById(updatedProducts);
        }
    }

    @Override
    public void setStatus(List<Long> longs, int status){
//        if (longs.contains(1L))throw  new AdminException("管理员不可修改");
        lambdaUpdate().set(Product::getStatus, status).in(Product::getId, longs).update();
    }

    @Override
    public List<ProductVO> getVOByNos(List<String> productNos) {

        MPJLambdaWrapper<Product> wrapper = new MPJLambdaWrapper<>(Product.class);
        wrapper
                .selectAsClass(Product.class, ProductVO.class)
                .selectAs(ProductCategory::getCategoryName, ProductVO::getCategoryName)
                .selectAs(Supplier::getSupplierName, ProductVO::getDefaultSupplierName)
                .leftJoin(ProductCategory.class, ProductCategory::getId, Product::getCategoryId)
                .leftJoin(Supplier.class, Supplier::getId, Product::getDefaultSupplierId)
                .in(Product::getProductNo, productNos);
        return baseMapper.selectJoinList(ProductVO.class, wrapper);
    }

    @Override
    public List<ProductVO> getVOByParam(String q) {
        MPJLambdaWrapper<Product> wrapper = new MPJLambdaWrapper<>(Product.class);
        wrapper
                .selectAsClass(Product.class, ProductVO.class)
                .selectAs(ProductCategory::getCategoryName, ProductVO::getCategoryName)
                .selectAs(Supplier::getSupplierName, ProductVO::getDefaultSupplierName)
                .leftJoin(ProductCategory.class, ProductCategory::getId, Product::getCategoryId)
                .leftJoin(Supplier.class, Supplier::getId, Product::getDefaultSupplierId)
                .like(Product::getProductNo, q)
                .or()
                .like(Product::getProductName, q)
                .list();
        return baseMapper.selectJoinList(ProductVO.class, wrapper);
    }

    @Override
    public void checkProduct(Long productId) {
        Product byId = getById(productId);
        if (byId==null||byId.getStatus()==0)throw new BillsException(MessageConstant.PRODUCT_IS_NOT_AVAILABLE);
    }

    @Async
    public CompletableFuture<Long> getCurrentStockAsync( ArrayList<Long> ids ) {
        QueryWrapper<Product> lqw = new QueryWrapper<>();
        lqw.select("SUM(current_stock) as sum")
                .eq("status", 1)
                .in(ids!=null&&!ids.isEmpty(),"category_id", ids);
        List<Map<String, Object>> maps = baseMapper.selectMaps(lqw);
        long currentStock = maps.get(0)==null? 0 : ((BigDecimal) maps.get(0).get("sum")).longValue();
        return CompletableFuture.completedFuture(currentStock);
    }

    private void getAllCategory(  List<ProductCategory> list, Long categoryId,List<Long> resList) {
        resList.add(categoryId);
        for (ProductCategory productCategory : list) {
            if (productCategory.getParentId().equals(categoryId))getAllCategory(list, productCategory.getId(), resList);
        }
    }

    @Async
    public CompletableFuture<Page<ProductVO>> getProductPageAsync(PageDTO pageDTO, String materialParam,  ArrayList<Long> ids ) {
        MPJLambdaWrapper<Product> queryWrapper = new MPJLambdaWrapper<>();
        queryWrapper
                .selectAsClass(Product.class, ProductVO.class)
               .selectAs(ProductCategory::getCategoryName, ProductVO::getCategoryName)
                .leftJoin(ProductCategory.class, ProductCategory::getId, Product::getCategoryId)
                .eq(Product::getStatus, 1)
                .and(StringUtils.hasText(materialParam), wrapper -> wrapper
                        .like(Product::getProductNo, materialParam)
                        .or()
                        .like(Product::getProductName, materialParam)
                )
                .in(ids!=null&&!ids.isEmpty(),Product::getCategoryId, ids);

        Page<ProductVO> resPage = baseMapper.selectJoinPage(new Page<>(pageDTO.getPage(), pageDTO.getSize()), ProductVO.class, queryWrapper);
        return CompletableFuture.completedFuture(resPage);
    }

    @Autowired
    private ApplicationContext applicationContext;

    public JSONObject getListWithStock(PageDTO pageDTO, String materialParam, Integer categoryId) throws ExecutionException, InterruptedException {
        // 获取当前类的代理对象
        ProductServiceImpl proxy = applicationContext.getBean(ProductServiceImpl.class);

        //获取id与父id
        ArrayList<Long> ids = new ArrayList<>();
        if (categoryId!=null){
            List<ProductCategory> list = productCategoryService.list();
            getAllCategory(list, Long.valueOf(categoryId),ids);
        }
        // 异步执行两个任务
        CompletableFuture<Long> currentStockFuture =proxy. getCurrentStockAsync(ids);//获取商品总数
        CompletableFuture<Page<ProductVO>> productPageFuture =proxy. getProductPageAsync(pageDTO, materialParam, ids);

        // 等待两个任务完成并获取结果
        CompletableFuture.allOf(currentStockFuture, productPageFuture).join();
        long currentStock = currentStockFuture.get();
        Page<ProductVO> resPage = productPageFuture.get();

        // 转换结果到VO
        List<ProductVO> voList = resPage.getRecords();
//                .stream()
//                .map(product -> BeanUtil.copyProperties(product, ProductVO.class))
//                .collect(Collectors.toList());

        // 构建响应结果
        return new JSONObject()
                .putOnce("total", resPage.getTotal())
                .putOnce("data", voList)
                .putOnce("currentStock", currentStock);
    }

    @Override
    public JSONObject findStockWarningCount(PageDTO pageDTO) {
        Page<Product> pageInfo = new Page<>(pageDTO.getPage(), pageDTO.getSize());
        Page<Product> page = lambdaQuery().eq(Product::getStatus, 1)
                .page(pageInfo);
        List<ProductReportVO> list = page.getRecords().stream().map(product -> {
            ProductReportVO vo = BeanUtil.copyProperties(product, ProductReportVO.class);
            vo.setLowSafeStock(product.getMinimumStock());
            int i = product.getMinimumStock() - product.getCurrentStock();
            vo.setLowCritical(Math.max(i, 0));
            return vo;
        }).toList();

        return new JSONObject()
                .putOnce("total", page.getTotal())
                .putOnce("data", list)
                .putOnce("currentStock", page.getRecords().stream().mapToLong(Product::getCurrentStock).sum());
    }


//    @Override
//    public JSONObject getListWithStock(PageDTO pageDTO, String materialParam, Integer categoryId) {
//        QueryWrapper<Product> lqw = new QueryWrapper<Product>();
//        lqw.select("SUM(current_stock) as sum")
//                .eq("status", 1);
//        List<Map<String, Object>> maps = baseMapper.selectMaps(lqw);
//        long currentStock = ((BigDecimal) maps.get(0).get("sum")).longValue();
//
////        // 构建带条件的分页查询
////        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
////        queryWrapper
////                .eq(Product::getStatus, 1)
////                // 处理材料参数查询条件（修正为OR逻辑）
////                .and(StringUtils.hasText(materialParam), wrapper -> wrapper
////                        .like(Product::getProductNo, materialParam)
////                        .or()
////                        .like(Product::getProductName, materialParam)
////                )
////                .eq(categoryId != null, Product::getCategoryId, categoryId);
////
//        MPJLambdaWrapper<Product> wrapper = new MPJLambdaWrapper<>(Product.class);
//        wrapper
//                .selectAsClass(Product.class, ProductVO.class)
//                .selectAs(ProductCategory::getCategoryName, ProductVO::getCategoryName)
//                .selectAs(Supplier::getSupplierName, ProductVO::getDefaultSupplierName)
//                .leftJoin(ProductCategory.class, ProductCategory::getId, Product::getCategoryId)
//                .leftJoin(Supplier.class, Supplier::getId, Product::getDefaultSupplierId)
//                .eq(Product::getStatus, 1)
//                // 处理材料参数查询条件（修正为OR逻辑）
//                .and(StringUtils.hasText(materialParam), i -> i
//                        .like(Product::getProductNo, materialParam)
//                        .or()
//                        .like(Product::getProductName, materialParam)
//                )
//                .eq(categoryId != null, Product::getCategoryId, categoryId);
//
//        // 执行分页查询
//        Page<ProductVO> pageInfo = new Page<>(pageDTO.getPage(), pageDTO.getSize());
//        Page<ProductVO> resPage = baseMapper.selectJoinPage(pageInfo , ProductVO.class,wrapper);
//
//        // 构建响应结果
//        return new JSONObject()
//                .putOnce("total", resPage.getTotal())
//                .putOnce("data", resPage.getRecords())
//                .putOnce("currentStock", currentStock);
//    }


    private static Map<Long, Integer> getIdToStock(List<OrderProductDetail> orderProductDetailList) {
        return orderProductDetailList.stream()
                .peek(i -> {
                    if (i.getQuantity() < 0) throw new RuntimeException("数量不能小于0");
                })
                .collect(Collectors.groupingBy(OrderProductDetail::getProductId,
                        Collectors.summingInt(OrderProductDetail::getQuantity)));
    }
}